package com.pxmeta.user.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.aliyun.oss.common.utils.HttpHeaders;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pxmeta.common.core.redis.RedisCache;
import com.pxmeta.common.utils.StringUtils;
import com.pxmeta.order.entity.Order;
import com.pxmeta.user.entity.User;
import com.pxmeta.user.entity.UserBill;
import com.pxmeta.user.entity.UserBillTypeEnum;
import com.pxmeta.user.entity.UserWithdraw;
import com.pxmeta.user.entity.dto.ApplyWithdrawDTO;
import com.pxmeta.user.entity.dto.UserWithdrawDTO;
import com.pxmeta.user.entity.vo.UserWithdrawVO;
import com.pxmeta.user.mapper.UserMapper;
import com.pxmeta.user.mapper.UserWithdrawMapper;
import com.pxmeta.user.service.IUserBillService;
import com.pxmeta.user.service.IUserService;
import com.pxmeta.user.service.IUserWithdrawService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

@Slf4j
@Service
public class UserWithdrawServiceImpl extends ServiceImpl<UserWithdrawMapper, UserWithdraw> implements IUserWithdrawService {

    @Autowired
    private IUserBillService userBillService;

    @Autowired
    private IUserService userService;

    @Override
    public Long applyWithdraw(Long userId, ApplyWithdrawDTO dto) {
        UserWithdraw userWithdraw = new UserWithdraw();
        userWithdraw.setUserId(userId);
        userWithdraw.setBank(dto.getBank());
        userWithdraw.setCardNo(dto.getCardNo());
        userWithdraw.setName(dto.getName());
        userWithdraw.setNumber(dto.getNumber());
        userWithdraw.setCardNumber(dto.getCardNumber());
        userWithdraw.setOpeningBank(dto.getOpeningBank());
        this.save(userWithdraw);
        return userWithdraw.getId();
    }

    @Override
    public IPage<UserWithdrawVO> getWithdrawList(Integer page, Integer size, Integer status) {
        return baseMapper.getWithdrawList(new Page<>(page, size),status);
    }

    @Override
    public void confirmWithdraw(UserWithdrawDTO dto) {
        Long id = dto.getId();
        UserWithdraw userWithdraw = this.getById(id);
        userWithdraw.setStatus(dto.getStatus());
        this.updateById(userWithdraw);
        LambdaQueryWrapper<UserBill> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserBill::getTargetId, id)
                .eq(UserBill::getUserId, userWithdraw.getUserId())
                .eq(UserBill::getType, UserBillTypeEnum.WITHDRAW.getType());
        UserBill userBill = userBillService.getOne(wrapper);
        userBill.setStatus(dto.getStatus());
        userBillService.updateById(userBill);
    }

    @Override
    public <T> void export(HttpServletResponse response, String fileName,
                           List<T> data, Class<T> clazz) {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");
            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream(), clazz)
                    .sheet("Sheet1")
                    // 设置单元格宽度自适应
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    // 设置单元格高度和字体
                    .registerWriteHandler(getHeightAndFontStrategy())
                    .doWrite(data);
            log.info("下载{}条记录到文件{}", data.size(), fileName);
        } catch (Exception e) {
            // 重置response
            log.error("文件下载失败" + e.getMessage());
            throw new RuntimeException("下载文件失败", e);
        }
    }

    @Override
    public Double getTotalWithdraw(String keyword, Integer status, String startTime, String endTime) {
        LambdaQueryWrapper<UserWithdraw> wrapper = Wrappers.lambdaQuery();
//        wrapper.eq(UserWithdraw::getStatus, 1);

        if (StringUtils.isNotBlank(keyword)){
            User user = userService.getByAccount(keyword);
            wrapper.eq(UserWithdraw::getUserId, user.getId());
        }
        if (StringUtils.isNotBlank(startTime)){
            wrapper.ge(UserWithdraw::getCreateTime, startTime)
                    .le(UserWithdraw::getCreateTime, endTime);
        }

        if (status != null){
            wrapper.eq(UserWithdraw::getStatus, status);
        }
        List<UserWithdraw> list = this.list(wrapper);

        double totalPrice = 0d;
        for (UserWithdraw userWithdraw : list) {
            totalPrice += userWithdraw.getNumber().doubleValue();
        }
        return BigDecimal.valueOf(totalPrice).setScale(2, RoundingMode.HALF_UP).doubleValue();

    }

    @Override
    public UserWithdraw getLastWithdrawRecord(Long userId) {
        LambdaQueryWrapper<UserWithdraw> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(UserWithdraw::getUserId, userId)
                .orderByDesc(UserWithdraw::getCreateTime)
                .last("limit 1");

        return this.getOne(wrapper);
    }


    /**
     * 自定义Excel导出策略，设置表头和数据行的字体和高度
     *
     * @return Excel导出策略
     */
    private HorizontalCellStyleStrategy getHeightAndFontStrategy() {
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 11);
        headWriteFont.setBold(true);
        headWriteCellStyle.setWriteFont(headWriteFont);
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        WriteFont contentWriteFont = new WriteFont();
        contentWriteFont.setFontHeightInPoints((short) 11);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    }
}
